package com.inspection.support;

import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions;
import fr.opensagres.xdocreport.converter.*;
import fr.opensagres.xdocreport.core.document.DocumentKind;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFldChar;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType;
import org.springframework.util.StringUtils;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author liukaiyang
 * @date 2018/3/14 11:23
 */
public class DocxUtil {

    /**
     * 将对象转为map
     *
     * @param obj
     * @return
     * @throws Exception
     */
    public static HashMap<String, String> convertToMap(Object obj)
            throws Exception {
        HashMap<String, String> map = new HashMap<>();
        Field[] fields = obj.getClass().getDeclaredFields();
        for (int i = 0, len = fields.length; i < len; i++) {
            String varName = fields[i].getName();
            boolean accessFlag = fields[i].isAccessible();
            fields[i].setAccessible(true);
            Object o = fields[i].get(obj);
            if (o != null) {
                map.put(varName, o.toString());
            }
            fields[i].setAccessible(accessFlag);
        }
        return map;
    }

    /**
     * 将word文档生成pdf
     *
     * @param in word文档 inputStream
     * @return
     */
    public static byte[] convertDocx2Pdf(InputStream in) throws IOException, XDocConverterException {
        Options options = Options.getFrom(DocumentKind.DOCX).to(ConverterTypeTo.PDF);
        PdfOptions pdfOptions = PdfOptions.create();
        pdfOptions.fontProvider(new ExtFontProvider());
        options.subOptions(pdfOptions);
        IConverter converter = ConverterRegistry.getRegistry().getConverter(options);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        converter.convert(in, out, options);
        return out.toByteArray();
    }

    /**
     * 将word文档生成预览图
     *
     * @param inputStream word文档
     * @return
     */
    public static byte[] covertDocx2Jpg(InputStream inputStream) throws IOException, XDocConverterException {
        byte[] pdfBytes = convertDocx2Pdf(inputStream);
        return covertPdf2Jpg(pdfBytes);
    }

    /**
     * 将pdf文档生成预览图
     *
     * @param pdfBytes pdf字节流
     * @return
     */
    public static byte[] covertPdf2Jpg(byte[] pdfBytes) throws IOException, XDocConverterException {
        PDDocument document = PDDocument.load(pdfBytes);
        return covertPdf2Jpg(document);
    }

    public static byte[] covertPdf2Jpg(InputStream inputStream) throws IOException, XDocConverterException {
        PDDocument document = PDDocument.load(inputStream);
//        PDPageTree pageTree=document.getPages();
        return covertPdf2Jpg(document);
    }

    private static byte[] covertPdf2Jpg(PDDocument document) throws IOException {
        int size = document.getNumberOfPages();
        List<BufferedImage> imageList = new ArrayList<BufferedImage>();
        for (int i = 0; i < size; i++) {
            BufferedImage image = new PDFRenderer(document).renderImageWithDPI(i, 100, ImageType.RGB);
            imageList.add(image);
        }
        document.close();
        return ImageUtil.combineImageVertical(imageList);
    }


    /**
     * word 文档模板变量填充
     * 模板文档(template.docx) 需要word版本: Word 2016, Word 2013, Word 2010, Word 2016 for Mac
     * <pre>
     *   预处理步骤:光标放在需要插入变量的位置->
     *   点击插入->文档部件->域->文档类别(文档自动化)-域名(DocVariable)->填入新名称(变量名称)
     *   快捷键ALT+F9可以查看或隐藏域
     * </pre>
     *
     * @param inputStream
     * @param params
     * @return
     * @throws IOException
     */
    public static XWPFDocument processDocVariable(InputStream inputStream, Map<String, String> params) throws IOException {
        XWPFDocument xwpfDocument = new XWPFDocument(inputStream);
        //获取段落
        Iterator<XWPFParagraph> iterator = xwpfDocument.getParagraphsIterator();
        DocxUtil.processDocVariable(iterator, params);
        //获取表格中的段落
        List<XWPFTable> tableList = xwpfDocument.getTables();
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        for (XWPFTable table : tableList) {
            rows = table.getRows();
            for (XWPFTableRow row : rows) {
                //获取行对应的单元格
                cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    DocxUtil.processDocVariable(cell.getParagraphs().iterator(), params);
                }
            }
        }
        return xwpfDocument;
    }

    /**
     * 处理文档中变量
     * 注意:此方法测试了一部分文档可用,未测试一些复杂样式的word文档
     *
     * @param iterator
     * @param params
     * @author liukaiyang
     */
    private static void processDocVariable(Iterator<XWPFParagraph> iterator, Map<String, String> params) {
        while (iterator.hasNext()) {
            XWPFParagraph paragraph = iterator.next();
            //获取段落中的run
            List<XWPFRun> xwpfRunList = paragraph.getRuns();
            String key = "";
            for (int i = 0; i < xwpfRunList.size(); i++) {
                XWPFRun xwpfRun = xwpfRunList.get(i);
                //1:获取域(docVariable)中的变量(key)
                List<CTText> texts = xwpfRun.getCTR().getInstrTextList();
                if (texts.size() > 0) {
                    StringBuilder runBuilder = new StringBuilder(2);
                    for (CTText text : texts) {
                        runBuilder.append(text.getStringValue());
                    }
                    String tempStr = runBuilder.toString();
                    if (!StringUtils.isEmpty(tempStr)) {
                        if (tempStr.trim().startsWith("DOCVARIABLE")) {
                            key = tempStr.replace("DOCVARIABLE", "")
                                    .replace("\\* MERGEFORMAT", "").trim();
//                            System.out.println("key=" + key);
                        }
                    }
                }
                //2:查找域,在结尾处添加变量值(XWPFRun)
                if (xwpfRun.getCTR().getFldCharList().size() > 0) {
                    CTFldChar fldChar = xwpfRun.getCTR().getFldCharList().get(0);

                    if (STFldCharType.BEGIN.equals(fldChar.getFldCharType())) {
//                        BeanUtils.copyProperties(xwpfRunList.get(i-1),tempRun);
                    }
                    if (STFldCharType.END.equals(fldChar.getFldCharType())) {
                        if (!StringUtils.isEmpty(params.get(key))) {
                            XWPFRun insertRun = paragraph.insertNewRun(i + 1);
                            insertRun.setBold(xwpfRun.isBold());
                            insertRun.setFontFamily(xwpfRun.getFontFamily(XWPFRun.FontCharRange.eastAsia));
                            insertRun.setItalic(xwpfRun.isItalic());
                            insertRun.setUnderline(xwpfRun.getUnderline());
                            if (xwpfRun.getFontSize() != -1) {
                                insertRun.setFontSize(xwpfRun.getFontSize());
                            }
//                            insertRun.setSubscript(xwpfRun.getSubscript());//这个属性影响转pdf,暂没找到相应文档这个属性是干嘛的
                            insertRun.setText(params.get(key));
                        }
                    }
                    
                }
            }
        }
    }
}
